package ccmap

import "sync"

type ConcurrentMap struct {
	innerMap map[string]interface{}
	locker   sync.RWMutex
}

func NewConcurrentMap() *ConcurrentMap {
	return &ConcurrentMap{innerMap: make(map[string]interface{})}
}

func (m *ConcurrentMap) Set(k string, v interface{}) {
	m.locker.Lock()
	defer m.locker.Unlock()
	m.innerMap[k] = v
}

func (m *ConcurrentMap) Delete(k string) {
	m.locker.Lock()
	defer m.locker.Unlock()
	delete(m.innerMap, k)
}

func (m *ConcurrentMap) Get(k string) interface{} {
	m.locker.RLock()
	defer m.locker.RUnlock()
	return m.innerMap[k]
}

func (m *ConcurrentMap) GetOrDefault(k string, _default interface{}) interface{} {
	m.locker.RLock()
	defer m.locker.RUnlock()
	i, ok := m.innerMap[k]
	if !ok {
		return _default
	}
	return i
}

func (m *ConcurrentMap) Exists(k string) bool {
	m.locker.RLock()
	defer m.locker.RUnlock()
	_, ok := m.innerMap[k]
	return ok
}

func (m *ConcurrentMap) ForEach(accept func(k string, v interface{})) {
	m.locker.RLock()
	defer m.locker.RUnlock()
	for k := range m.innerMap {
		accept(k, m.innerMap[k])
	}
}

func (m *ConcurrentMap) Find(accept func(k string, v interface{}) bool) (find bool) {
	for k := range m.innerMap {
		find = accept(k, m.innerMap[k])
		if find {
			return
		}
	}
	return
}

func (m *ConcurrentMap) Size() int {
	m.locker.RLock()
	defer m.locker.RUnlock()
	return len(m.innerMap)
}
